import { generatePublicKey } from '@/api/user'
import store from '@/store'
import { getUuid } from '@/utils/common'
import axios from 'axios'
import qs from 'qs'
import { Toast } from 'vant'

// 农行国密
// 外网国密
// import crypto from '@/utils/externalSmCryptoUtil'

const commonParameter = {
  appChannelCode: 'JKWX',
  appCityCode: 'string',
  appId: 'sysnum-smct',
  // "appId": "jkbp00user000O2022030700010004",
  appIpAddress: 'string',
  appMacAddress: 'string',
  channelCode: 'smct-zyapp',
  // "channelCode": "10002",
  cityCode: 'string',
  encryptData: 'string',
  encryptType: 'string',
  extension: {
    additionalProp1: 'string',
    additionalProp2: 'string',
    additionalProp3: 'string'
  },
  extensionObject: {},
  flowNum: 0,
  msgType: 'string',
  nonceString: 'string',
  requestId: 'string',
  signStamp: 'string',
  signType: 'string',
  specVersion: 'string',
  terminalId: 'string',
  // "timestamp": new Date().valueOf(), // TODO TIMEDIFF
  timestamp: 0,
  trCode: 'string',
  trVersion: 'string',
  uniqueId: 'string'
  // "userId": "string"
}

const local = false

const baseURL = process.env.VUE_APP_BASE_API
const config = {
  timeout: 30 * 1000,
  headers: {
    'content-type': 'application/json;charset=UTF-8',
    smartcanteen: 'smartcanteen',
    'x-requested-with': 'XMLHttpRequest',
    Pragma: 'no-cache',
    'x-app-id': 'jkbp-user'
    // "referer":"https://devappid.hybrid.alipay-eco.com/undefined/dev/index.html#pages/enterpriseList/enterpriseList?__appxPageId=1"
  },
  baseURL: baseURL + '/gateway/smct-pay',
  data: commonParameter
}

const instance = axios.create(config)

// 公钥请求等待队列
let isRequestingPublicKey = false
let requestWaitingQueue = []
// 签名白名单
const signWhiteList = () => {
  return ['TO000245']
}

// http request 拦截器
instance.interceptors.request.use(
  (config) => {
    // const token = cookieGet('App-token')
    // if (token) {
    //   config.headers.token = token
    // }else{
    config.headers.token = 'b3dc8786-e66a-4a94-a49b-a2d9efae844b1722848982680'
    // }

    if (config.responseType === 'blob') {
      config.headers['X-File-Down'] = true
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

// http response 拦截器
instance.interceptors.response.use(
  (response) => {
    return response
  },
  (error) => {
    return Promise.reject(error)
  }
)

// ======================== 请求成功回调 ===================

// 成功回调函数
const successCheck = (resp) => {
  // 附件下载预览不管是否开启加解密直接返回
  if (resp.config.responseType === 'blob') {
    return resp.data
  }
  // mockjs不管是否开启加解密直接返回
  if (resp.config.url.indexOf('/mock') === 0) {
    return resp.data
  }
  // 如果网关报错，data不会被加密
  if (resp.data.resCode !== 0 && resp.data.resCode !== 200) {
    return Promise.reject(resp.data)
  }
  // 没有开启加密,不解密,直接获取私有报文
  // privateData 为响应报文中的私有报文
  let privateData
  if (!store.state.encryptParam.encryptOn) {
    privateData = resp.data.data
  } else {
    // 若开启加密需要判断返回数据是否需要解密
    // 如果有交易码通过交易码判断返回数据是否解密
    // if (resp.data.trCode && !signWhiteList().includes(resp.data.trCode)) {
    //   privateData = decryptBySM(resp.data)
    // } else {
    privateData = resp.data.data
    // }
  }
  // 私有报文
  const { respCode, data } = privateData
  if (respCode !== 'FJKBP0000') {
    // 回调状态码错误
    // 如果出现错误信息，则将整个报文抛出
    return Promise.reject(resp.data)
  }
  return data
}

// ======================= 请求失败处理 ======================

// 失败回调函数
const errorCheck = (error) => {
  // 处理网络超时、连接失败等前端错误
  if (error instanceof Error) {
    if (
      !error.config.url.includes(
        '/smartcanteen/querycompanyprovider/findHarmony'
      )
    ) {
      // console.log(error.config.url,'error.data')
      Toast({
        message: '网络异常',
        duration: 3000
      })
    }
    return Promise.reject(error)
  }

  const errorResponse = error.response
  // 业务错误，error为整个响应报文
  if (!errorResponse) {
    if (error.data.respCode === 'FJKBP0000') {
      // token失效
      logout()
    }
    return Promise.reject(error.data)
  }

  // 网络错误，errorResponse为响应体
  const statusCode = errorResponse.status
  if (statusCode >= 400) {
    if (
      errorResponse.data &&
      (errorResponse.data.resCode === '0033' ||
        errorResponse.data.resCode === '0077' ||
        errorResponse.data.resCode === '0088')
    ) {
      // token失效
      logout()
    }
    Toast({
      message: errorResponse.data?.resMessage.replace(/\./g, '') || '网络错误',
      duration: 3000
    })
  }
  // 针对网络错误,抛出整个响应报文
  return Promise.reject(error.response.data)
}

const execute = (config) => {
  return instance(config).then(successCheck).catch(errorCheck)
}

// 公共参数
const addCommonParameter = (common) => {
  const param = commonParameter()
  return Object.assign(param, common)
}

// token过期处理
const logout = () => {}

export default {
  postJson(url, data, common) {
    return new Promise((resolve, reject) => {
      const requestFnc = (url, dataObj) => {
        return execute({
          method: 'post',
          url: url,
          data: dataObj,
          headers: {
            'Content-Type': 'application/json'
          }
        })
      }

      // 不签名
      if (!store.state.encryptParam.encryptOn) {
        return resolve(
          requestFnc(url, {
            data: data,
            ...addCommonParameter(common)
          })
        )
      }

      // 签名--已经获取签名公钥
      if (store.state.encryptParam.SM2_Pubkey) {
        return resolve(requestFnc(url, addSMParameter(data, common)))
      }

      // 签名--未获取到签名公钥
      if (!isRequestingPublicKey) {
        isRequestingPublicKey = true
        requestWaitingQueue.push({
          url,
          data,
          common,
          resolve,
          reject
        })
        // 获取公钥
        store.commit('encryptParam/SET_H5ENCRYPTKEY', getUuid())
        generatePublicKey({})
          .then((result) => {
            if (result) {
              store.commit('SET_TIMEDIFF', result.timeDiff)
              store.commit('encryptParam/SET_SM2_PUBKEY', result.key)
              requestWaitingQueue.forEach((item) => {
                // 获取到公钥后，重新请求
                const { url, data, common } = item
                item.resolve(requestFnc(url, addSMParameter(data, common)))
              })
              isRequestingPublicKey = false
              requestWaitingQueue = []
            } else {
              isRequestingPublicKey = false
              throw new Error('获取公钥失败')
            }
          })
          .catch((error) => {
            isRequestingPublicKey = false
            requestWaitingQueue.forEach((item) => {
              item.reject(error)
            })
          })
      } else {
        // 多个异步请求放入请求队列中
        requestWaitingQueue.push({
          url,
          data,
          common,
          resolve,
          reject
        })
      }
    })
  },

  // 附件类上传
  uploadFile(url, data) {
    return execute({
      method: 'post',
      url: url,
      data: data,
      headers: {
        'Content-Type': 'multipart/form-data',
        'X-Use-Code-Enable': false
      }
    })
  },

  // 附件类下载预览
  downloadFile(url, data, common) {
    let dataObj = {}
    if (store.state.encryptParam.encryptOn) {
      dataObj = addSMParameter(data, common)
    } else {
      dataObj = {
        data: data,
        ...addCommonParameter(common)
      }
    }
    return execute({
      method: 'post',
      url: url,
      data: dataObj,
      responseType: 'blob'
    })
  },

  // 不带加密报文 用于请求获取密钥的接口
  postBase(url, data, common) {
    const param = addCommonParameter(common) // 整理公共请求报文
    param.encryptType = 'SM4' // 密钥类型
    return execute({
      method: 'post',
      url: url,
      data: {
        data: data,
        ...param
      }
    })
  },

  postForm(url, data) {
    return execute({
      method: 'post',
      url: url,
      data: data,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
      },
      transformRequest: [
        function(data) {
          // 数据序列化
          return qs.stringify(data)
        }
      ]
    })
  },

  // mockjs
  get(url, data) {
    return execute({
      method: 'get',
      url: url,
      params: data
    })
  },
  post(url, data) {
    return execute({
      method: 'post',
      url: url,
      data: { ...commonParameter, data }
    })
  }
}
